package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.PageResultVo;
import com.itheima.wemedia.dto.AuthReqDto;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.dto.WmNewsDtoSave;
import com.itheima.wemedia.dto.WmNewsPageReqDto;
import com.itheima.wemedia.mapper.WmMaterialMapper;
import com.itheima.wemedia.mapper.WmNewsMaterialMapper;
import com.itheima.wemedia.mapper.WmUserMapper;
import com.itheima.wemedia.pojo.WmMaterial;
import com.itheima.wemedia.pojo.WmNews;
import com.itheima.wemedia.mapper.WmNewsMapper;
import com.itheima.wemedia.pojo.WmNewsMaterial;
import com.itheima.wemedia.pojo.WmUser;
import com.itheima.wemedia.service.WmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.wemedia.service.WmUserService;
import com.itheima.wemedia.vo.WmNewsVo;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.RequestContextUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @description <p>自媒体图文内容信息 业务实现</p>
 *
 * @version 1.0
 * @package com.itheima.wemedia.service.impl
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Override
    public void submit(boolean draft, WmNewsDtoSave wmNewsDtoSave) {
        LocalDateTime now = LocalDateTime.now();
        //1.添加文章数据
        //1.1创建pojo
        WmNews pojo = new WmNews();
        BeanUtils.copyProperties(wmNewsDtoSave,pojo);
        //如果没有填发布时间，当下时间来填
        if (pojo.getPublishTime()==null){
            pojo.setPublishTime(now);
        }
        //2.设置属性
        pojo.setUserId(Long.parseLong(RequestContextUtil.getUserId()));
        if (null == wmNewsDtoSave.getPublishTime()){
            pojo.setPublishTime(now);
        }
        if (!draft){
            pojo.setSubmitedTime(now);
        }
        pojo.setStatus(draft?0:1);
        //如果封面图片有值则以逗号分开
        if (!CollectionUtils.isEmpty(wmNewsDtoSave.getImages())){
            String join = String.join(",", wmNewsDtoSave.getImages());
            pojo.setImages(join);
        }
        pojo.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);
        //设置type的值
        //根据图片的数量 来设置type的值，还有封面
        //count=0 设置type=无图，封面为""
        //count<3 设置type=单图, 封面为取第一张图片
        //count>=3 设置type=多图,封面取前3张图片
        setWmNewsType(wmNewsDtoSave,pojo);
        //save方法，获取新增文章的id
        if (null == wmNewsDtoSave.getId()) {
            save(pojo);
            pojo.setCreatedTime(now);
        }else {
            updateById(pojo);
            removeWmNewsMaterialRelationship(pojo.getId());
        }
        //添加文章与素材的关系
        addWmNewsMaterialRelationship(pojo);

        // 文章自动审核处理
        if(pojo.getStatus()== BusinessConstants.WmNewsConstants.STATUS_SUBMIT){
            //如果是提交待审核的，则发消息给kafka,消息内容为文章的id
            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_AUTO_SCAN_TOPIC, pojo.getId().toString());
        }
    }

    /**
     * 分页查询
     * @param dto
     * @return
     */
    @Override
    public PageResultVo<WmNews> findPage(WmNewsPageReqDto dto) {
        //构建page对象
        Page<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //设置查询条件
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null !=dto.getStatus(),WmNews::getStatus,dto.getStatus());
        wrapper.eq(WmNews::getUserId,RequestContextUtil.getUserId());
        wrapper.eq(null != dto.getChannelId(),WmNews::getChannelId,dto.getChannelId());
        wrapper.ge(null != dto.getBeginPubDate(),WmNews::getPublishTime,dto.getBeginPubDate());
        wrapper.lt(null != dto.getEndPubDate(),WmNews::getPublishTime,dto.getEndPubDate());
        wrapper.like(null != dto.getKeyword(),WmNews::getTitle,dto.getKeyword());
        //查询
        page(pageInfo,wrapper);
        //构建返回对象
        return PageResultVo.pageResult(dto.getPage(),dto.getSize(),pageInfo.getTotal(),pageInfo.getRecords());

    }

    /**
     * 根据id查询文章
     * @param id
     * @return
     */
    @Override
    public WmNews findWmNewsById(Long id) {
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WmNews::getUserId,RequestContextUtil.getUserId());
        wrapper.eq(WmNews::getId,id);

        WmNews wmNews = wmNewsMapper.selectOne(wrapper);
        return wmNews;
    }

    /**
     * 根据id删除文章
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews.getStatus() == BusinessConstants.WmNewsConstants.STATUS_PUBLISHED ||
            wmNews.getEnable() == BusinessConstants.WmNewsConstants.ENABLE_ON){
            throw new LeadNewsException("文章已上架，不能删除");
        }
        removeById(id);
    removeWmNewsMaterialRelationship(id);
    }

    /**
     * 文章上架，下架
     * @param map
     */
    @Override
    public void downOrUp(Map<String, String> map) {
        String id = map.get("id");
        String enable = map.get("enable");
      //参数校验
        if (null == id||null == enable||Integer.parseInt(enable)>1||Integer.parseInt(enable)<0){
            throw new LeadNewsException(HttpCodeEnum.PARAM_INVALID);
        }
        //通过id查询
        WmNews wmNews = getById(id);
        //状态不为9不能上下架
        if (wmNews.getStatus()!=9){
            throw new LeadNewsException("文章未发布，不能上架或下架");
        }
        WmNews onwWmNews = new WmNews();
        onwWmNews.setId(Long.parseLong(id));
        if (Integer.parseInt(enable)==0){
          onwWmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_OFF);
          onwWmNews.setStatus(BusinessConstants.WmNewsConstants.STATUS_SUBMIT);
        }else {
           onwWmNews.setEnable(BusinessConstants.WmNewsConstants.ENABLE_ON);
        }
        boolean flag = updateById(onwWmNews);
        if (flag){
            //发送变更
            Long articleId = wmNews.getArticleId();
            //发送给kafka(articleId,enable
            Map<String,Long> msgMap= new HashMap<>();
            msgMap.put("articleId",articleId);
            msgMap.put("enable",Long.parseLong(enable));

            //转成json格式字符串
            String json = JSON.toJSONString(msgMap);

            kafkaTemplate.send(BusinessConstants.MqConstants.WM_NEWS_DOWN_OR_UP_TOPIC,json);
        }
    }

    @Override
    public PageResultVo findPage4Admin(WmNewsPageReqDto dto) {
        //1.设置page对象
        Page<WmNews> pageInfo = new Page<>(dto.getPage(), dto.getSize());
        //2.设置查询条件
        LambdaQueryWrapper<WmNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(dto.getStatus() != null,WmNews::getStatus,dto.getStatus());
        wrapper.like(!StringUtils.isEmpty(dto.getTitle()),WmNews::getTitle,dto.getTitle());
        //3.查询
        page(pageInfo,wrapper);
        //4.获取查询结果集
        List<WmNews> wmNewsList = pageInfo.getRecords();
        //5.解析提取结果集中的用户id
        List<WmNewsVo> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(wmNewsList)){
            List<Long> userIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //6.通过用户id查询用户信息
            Map<Long, WmUser> userInfoMap = getUserInfoByIds(userIds);
            //7.WmNews转成WmNewsVo
            voList = wmNewsList.stream().map(wmNews -> WmNewsVo.build(wmNews, userInfoMap.get(wmNews.getUserId()))).collect(Collectors.toList());
        }
        //8.构建结果集返回
        return PageResultVo.pageResult(dto.getPage(),dto.getSize(),pageInfo.getTotal(),voList);
    }

    /**
     * 人工审核-通过
     * @param dto
     */
    @Override
    public void authPass(AuthReqDto dto) {
        WmNews pojo = new WmNews();
        pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL_PASS);
        pojo.setId(dto.getId());
        updateById(pojo);
    }

    /**
     * 人工审核-驳回
     * @param dto
     */
    @Override
    public void authFail(AuthReqDto dto) {
        WmNews pojo = new WmNews();
        pojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
        pojo.setReason(dto.getMsg());
        pojo.setId(dto.getId());
        updateById(pojo);
    }

    /**
     * 通过id查询文章详情
     * @param id
     * @return
     */
    @Override
    public WmNewsVo findById(Long id) {
        WmNews wmNews = getById(id);
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        WmNewsVo wmNewsVo = WmNewsVo.build(wmNews, wmUser);
        return wmNewsVo;

    }

    /**
     * 查询需要同步的文章状态为8
     * @param dto
     * @return
     */
    @Override
    public List<WmNewsVo> list4ArticleSync(WmNewsPageReqDto dto) {
        //1.构建条件status=8
        //2.查询得到wmNews表
        List<WmNews> wmNewsList = query().eq("status", dto.getStatus())
                .lt(null != dto.getEndPubDate(),"publish_time",dto.getEndPubDate()).list();
        //3.获取所有作者
        List<WmNewsVo> voList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(wmNewsList)){
            //自媒体账号id
            List<Long> userIds = wmNewsList.stream().map(WmNews::getUserId).collect(Collectors.toList());
            //4.批量查询wmUser表
            List<WmUser> wmUsers = wmUserMapper.selectBatchIds(userIds);
            Map<Long,WmUser> wmUserInfoMap = wmUsers.stream()
                    .collect(Collectors.toMap(WmUser::getId,Function.identity()));
            //5.转成wmNewsvo
            voList = wmNewsList.stream().map(wmNews -> WmNewsVo.build(wmNews,wmUserInfoMap.get(wmNews.getUserId()))).collect(Collectors.toList());
        }
        return voList;
    }

    /**
     * 通过用户id集合批量查询用户信息
     * @param userIds
     * @return
     */
    private Map<Long, WmUser> getUserInfoByIds(List<Long> userIds) {
     Map<Long,WmUser> map = new HashMap<>();
     if (!CollectionUtils.isEmpty(userIds)){
         List<WmUser> wmUsers = wmUserMapper.selectBatchIds(userIds);
        map = wmUsers.stream().collect(Collectors.toMap(WmUser::getId, Function.identity()));
     }
     return map;
    }


    private void addWmNewsMaterialRelationship(WmNews pojo) {
        //从内容中获取封面图片和内容中图片
        HashSet<String> pics = new HashSet<>();
        List<String> coverList = new ArrayList<>();
        //处理封面中的图片
        if (!StringUtils.isEmpty(pojo.getImages())){
            //封面图片数组去前缀
            String[] split = pojo.getImages().split(",");
            //封面图片集合
            coverList = Arrays.stream(split).map(this::removePrefix).collect(Collectors.toList());
            pics.addAll(coverList);
        }
        //处理内容图片
        String content = pojo.getContent();
        List<String> collectList = new ArrayList<>();
        if (!StringUtils.isEmpty(content)){
            List<WmNewsContentNodeDto> contentNodeDtoList = JSON.parseArray(content, WmNewsContentNodeDto.class);
            collectList = contentNodeDtoList.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                    .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
            pics.addAll(collectList);
        }
        //通过图片地址查询素材表,得到素材id
        LambdaQueryWrapper<WmMaterial> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(WmMaterial::getUrl,pics);
        List<WmMaterial> materialList = wmMaterialMapper.selectList(wrapper);
        Map<String, Long> materialMap = materialList.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        //封面中的图片
        addNewsMaterialRelationship(pojo.getId(),coverList,materialMap, BusinessConstants.WmNewsConstants.WM_COVER_REFERENCE);
        //内容中的图片
        addNewsMaterialRelationship(pojo.getId(),collectList,materialMap, BusinessConstants.WmNewsConstants.WM_CONTENT_REFERENCE);

    }

    private void addNewsMaterialRelationship(Long id, List<String> coverList, Map<String, Long> materialMap, int wmCoverReference) {
        for (int i = 0; i < coverList.size(); i++) {
            WmNewsMaterial pojo = new WmNewsMaterial();
            pojo.setType(wmCoverReference);
            pojo.setOrd(i+1);
            pojo.setNewsId(id);
            Long aLong = materialMap.get(coverList.get(i));
            pojo.setMaterialId(aLong);
            wmNewsMaterialMapper.insert(pojo);

        }
    }

    private void removeWmNewsMaterialRelationship(Long id) {
        wmNewsMaterialMapper.deleteByMap(Collections.singletonMap("news_id",id));
    }

    private void setWmNewsType(WmNewsDtoSave wmNewsDtoSave, WmNews pojo) {
        //获取type的值，如果type的值=-1，则为自动
        if (wmNewsDtoSave.getType()==-1){
            //提取文章的图片
            String content = wmNewsDtoSave.getContent();
            if (!StringUtils.isEmpty(content)){
                List<WmNewsContentNodeDto> contentNodeDtoList = JSON.parseArray(content, WmNewsContentNodeDto.class);
                List<String> stringList = contentNodeDtoList.stream().filter(n -> BusinessConstants.WmNewsConstants.CONTENT_IMAGE.equals(n.getType()))
                        .map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
                int size = stringList.size();
                if (size==0){
                    pojo.setImages("");
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_NONE_IMG);
                }else if (size<3) {
                    pojo.setImages(stringList.get(0));
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_SINGLE_IMG);
                }else {
                    pojo.setType(BusinessConstants.WmNewsConstants.TYPE_MULTIPLE_IMG);
                    String images = stringList.stream().limit(3).collect(Collectors.joining(","));
                    pojo.setImages(images);
                }
            }
        }
    }

    private String removePrefix(String url){
        //http://192.168.211.128:8080/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://192.168.211.128/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        //http://127.0.0.1/group1/M00/00/00/wKjTgGK4BGuASyi-AAiWSBNgF8M620.png
        return url.replaceAll("http://((\\d){1,3}\\.){3}(\\d){1,3}:?(\\d){0,5}\\/", "");
    }
}
